OpenCV 之 角点检测 您所在的位置:网站首页 opencv 直角检测 OpenCV 之 角点检测

OpenCV 之 角点检测

2023-10-13 13:07| 来源: 网络整理| 查看: 265

    角点 (corners) 的定义有两个版本:两条边缘的交点,或者,邻域内具有两个主方向的特征点

    从人眼来看,角点是图像亮度发生剧烈变化的点 或 边缘曲线上曲率为极大值的点。例如,下图 E 和 F 便是典型的角点

        

1  检测思路

    在图像中定义一个局部小窗口,然后沿各个方向移动这个窗口,则会出现 a) b) c) 三种情况,分别对应平坦区、边缘和角点

     a)  窗口内的图像强度,在窗口向各个方向移动时,都没有发生变化,则窗口内都是 “平坦区”,不存在角点

     b)  窗口内的图像强度,在窗口向某一个 (些) 方向移动时,发生较大变化;而在另一些方向不发生变化,那么,窗口内可能存在 “边缘”

     c)  窗口内的图像强度,在窗口向各个方向移动时,都发生了较大的变化,则认为窗口内存在 “角点”

         

                 a)  flat region              b)  edge                     c)  corner

2  Harris 角点 2.1  泰勒展开

    图像在点 $(x,y) $ 处的灰度值为 $I(x, y)$,当在 $x$ 方向上平移 $\Delta u$,且 $y$ 方向上平移 $\Delta v$ 时,图像灰度值的变化为

 \qquad E(\Delta u,\Delta v) = \sum\limits_{x,y} \, \underbrace{w(x,y)}_\text{window function} \; [\underbrace{I(x+\Delta u, y+\Delta v)}_\text{shifted intensity} - \underbrace{I(x, y)}_\text{intensity}]^2

    $I(x,y)$ 的偏导数分别记为 $I_x$ 和 $I_y$,则上式用一阶泰勒级数近似展开

    \qquad \sum\limits_{x,y} \; [I(x+\Delta u, y+\Delta v) - I(x, y)]^2 \approx \sum\limits_{x,y} \; [I(x, y) +\Delta uI_x + \Delta vI_y - I(x, y)]^2 = \sum\limits_{x,y} \; [\Delta u^2I_x^2 + 2\Delta u \Delta vI_x I_y + \Delta v^2I_y^2 ]

    写成矩阵形式

    \qquad E(\Delta u,\Delta v) \approx \begin{bmatrix} \Delta u & \Delta v \end{bmatrix} \left ( \displaystyle \sum_{x,y} w(x,y) \begin{bmatrix} I_x^{2} & I_{x}I_{y} \\ I_xI_{y} & I_{y}^{2} \end{bmatrix} \right ) \begin{bmatrix} \Delta u \\ \Delta v \end{bmatrix}

    则有

    \qquad E(\Delta u,\Delta v) \approx \begin{bmatrix} \Delta u & \Delta v \end{bmatrix} M \begin{bmatrix} \Delta u \\ \Delta v \end{bmatrix}, 假定 M = \displaystyle \sum_{x,y} w(x,y) \begin{bmatrix} I_x^{2} & I_{x}I_{y} \\ I_xI_{y} & I_{y}^{2} \end{bmatrix}

2.2  判别方法  

    定义角点响应值 $R = det(M) - k(trace(M))^{2} = \lambda_{1} \lambda_{2} - k (\lambda_{1}+\lambda_{2})^2 $,根据响应值的大小,判断小窗口内是否包含角点:

     1) “平坦区”:|R| 小的区域,即 $\lambda_1$ 和 $\lambda_2$ 都小;

     2)  “边缘”: R > \lambda_2$ 或反之;

     3)  “角点”: R 大的区域,即 $\lambda_1$ 和 $\lambda_2$ 都大且近似相等    

    为了便于直观理解,绘制成 $\lambda_1-\lambda_2$ 平面如下图:

        

2.3  cornerHarris()

    OpenCV 中 Harris 角点检测的函数为: 

void cornerHarris ( InputArray src, // 输入图像 (单通道,8位或浮点型) OutputArray dst, // 输出图像 (类型 CV_32FC1,大小同 src) int blockSize, // 邻域大小 int ksize, // Sobel 算子的孔径大小 double k, // 经验参数,取值范围 0.04 ~ 0.06 int borderType = BORDER_DEFAULT // 边界模式 )  2.4  代码示例 #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" using namespace cv; // Harris corner parameters int kThresh = 150; int kBlockSize = 2; int kApertureSize = 3; double k = 0.04; int main() { // read image Mat src, src_gray; src = imread("building.jpg"); if(src.empty()) return -1; cvtColor(src, src_gray, COLOR_BGR2GRAY); Mat dst, dst_norm, dst_norm_scaled; // Harris corner detect cornerHarris(src_gray, dst, kBlockSize, kApertureSize, k); normalize(dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1); convertScaleAbs(dst_norm, dst_norm_scaled); // draw detected corners for(int j=0; j < dst_norm.rows; j++) { for(int i=0; i kThresh) { circle(src, Point(i, j), 2, Scalar(0,255,0)); } } } imshow("harris corner", src); waitKey(0); }

    检测结果:

    

3  Shi-Tomasi 角点

  Shi-Tomasi 角点是 Harris 角点的改进,在多数情况下,其检测效果要优于 Harris。二者的区别在于,Shi-Tomasi 选取 $\lambda_1$ 和 $\lambda_2$ 中的最小值,作为新的角点响应值 $R$

  \qquad R = min(\lambda_1, \lambda_2)

  则相应的 $\lambda_1-\lambda_2$ 平面为:

   

3.1  goodFeaturesToTrack()

    OpenCV 中 Shi-Tomasi 角点检测函数为:

void goodFeaturesToTrack ( InputArray image, // 输入图像 (单通道,8位或浮点型32位) OutputArray corners, // 检测到的角点 int maxCorners, // 最多允许返回的角点数量 double qualityLevel, // double minDistance, // 角点间的最小欧拉距离 InputArray mask = noArray(), // int blockSize = 3, // bool useHarrisDetector = false, // double k = 0.04 // ) 3.2  代码示例 #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" using namespace cv; using namespace std; int kMaxCorners = 1000; double kQualityLevel = 0.1; double kMinDistance = 1; int main() { // read image Mat src, src_gray; src = imread("building.jpg"); if (src.empty()) return -1; cvtColor(src, src_gray, COLOR_BGR2GRAY); // Shi-Tomasi corner detect vector corners; goodFeaturesToTrack(src_gray, corners, kMaxCorners, kQualityLevel, kMinDistance); // draw and show detected corners for (size_t i = 0; i < corners.size(); i++) { circle(src, corners[i], 2.5, Scalar(0, 255, 0)); } imshow("Shi-Tomasi corner", src); waitKey(0); }

   检测结果:

   

4  角点检测的实现

   分析 cornerHarris() 源码,复现计算步骤:Sobel 算子求解 dx 和 dy  ->  矩阵 M  -> boxFilter  -> 每个像素的角点响应值 R,对应 C++ 代码实现如下:

#include #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" using namespace cv; using namespace std; int kApertureSize = 3; int kBlockSize = 2; double k = 0.04; int kThresh = 150; int main() { // read image Mat src, src_gray; src = imread("chessboard.png"); if (src.empty()) return -1; cvtColor(src, src_gray, COLOR_BGR2GRAY);   // determine scale double scale = (double)(1 150) { circle(src, Point(i, j), 2, Scalar(0, 255, 0)); } } } imshow("Harris corner", src); waitKey(0); }

   检测结果:将求得的角点响应值$R$,输出 txt 文件,与 cornerHarris() 输出的 $R$ 进行比较,结果几乎完全相同 (只有几处小数点后7位的值不同)

5  亚像素角点检测  5.1  cornerSubpix()

    亚像素角点提取的函数 cornerSubPix(),常用于相机标定中,定义如下:

void cornerSubPix( InputArray image, // 输入图象(单通道,8位或浮点型) InputOutputArray corners, // 亚像素精度的角点坐标 Size winSize, // 搜索窗口尺寸的 1/2 Size zeroZone, // TermCriteria criteria // 迭代终止准则 ) 5.2  代码示例 #include #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" using namespace cv; using namespace std; int kMaxCorners = 40; double kQualityLevel = 0.01; double kMinDistance = 50; int main() { // read image Mat src, src_gray; src = imread("chessboard.png"); if (src.empty()) return -1; cvtColor(src, src_gray, COLOR_BGR2GRAY); // Shi-Tomasi corner detect vector corners; goodFeaturesToTrack(src_gray, corners, kMaxCorners, kQualityLevel, kMinDistance); // draw and show detected corners for (size_t i = 0; i < corners.size(); i++) { circle(src, corners[i], 3, Scalar(0, 255, 0)); } imshow("Shi-Tomasi corner", src); imwrite("subpix.png", src); TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 40, 0.001); // find corner positions in subpixel cornerSubPix(src_gray, corners, Size(5, 5), Size(-1, -1), criteria); for (size_t i = 0; i < corners.size(); i++) { cout


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有